// 注意:
// 把 xdebug 相关的内容挪到 .cpp 中，由于 memory.hpp 是一个相对底层的模块，
// 各个其他模块都可能用到它，为了避免出现环形包含，需要保证简单的 hpp
#undef  xuser
#define xuser mixc::utils_memory::inc
#include"configure/switch.hpp"
#include"concurrency/lock/atom_add.hpp"
#include"concurrency/lock/atom_load.hpp"
#include"concurrency/lock/atom_sub.hpp"
#include"macro/xdebug.hpp"
#include"macro/xmaybe_unused.hpp"

#if xuse_mixc_rtos
    #include"extern/rtos/memory.hpp"

    namespace mixc::utils_memory{
        extern voidp tiny_alloc(xmaybe_unused asciis name, uxx bytes){
            auto ptr = inc::g_memory.alloc(bytes);
            xdebug(im_alloc_with_initial, name, ptr, bytes);
            return ptr;
        }

        extern void tiny_free(xmaybe_unused asciis name, voidp ptr, uxx bytes){
            xdebug(im_free, name, ptr, bytes);
            inc::g_memory.free(ptr, bytes);
        }
    }

    namespace mixc::utils_memory::origin::memory{
        extern uxx used_bytes(){
            // 注意:
            // 在精确统计内存使用时，不要多次调用 get_statistic() 分别获取字段，
            // 因为每一个 get_statistic() 获取舜时值都可能不一样
            return inc::memory::get_statistic().used_bytes();
        }

        extern uxx alive_object(){
            // 同上
            return inc::memory::get_statistic().alive_object;
        }
    }

#else
    #if xuse_mixc_allocator
        #include"utils/private/memory_flow.hpp"

        namespace mixc::utils_memory{
            xthread_local(mem, inc::memory_flow);

            extern voidp tiny_alloc(xmaybe_unused asciis name, uxx bytes){
                auto ptr = mem->alloc(bytes);
                xdebug(im_alloc, name, ptr, bytes);
                return ptr;
            }

            extern void tiny_free(xmaybe_unused asciis name, voidp ptr, uxx bytes){
                xdebug(im_free, name, ptr, bytes);
                mem->free(ptr, bytes);
            }
        }

        namespace mixc::utils_memory::origin::memory{
            extern uxx used_bytes(){
                return mem->used_bytes();
            }

            extern uxx alive_object(){
                return mem->alive_object();
            }
        }

    #else
        #include<malloc.h>

        namespace mixc::utils_memory{
            inline uxx g_used_bytes;
            inline uxx g_alive_object;

            extern voidp tiny_alloc(xmaybe_unused asciis name, uxx bytes){
                // 按 16 字节对齐
                inc::atom_add(& g_used_bytes, bytes);
                inc::atom_add(& g_alive_object, uxx{1});
                bytes           = (bytes + 0xf) & ~0xf;
                auto ptr        = ::malloc(bytes);

                xdebug(im_alloc, name, ptr, bytes);
                return ptr;
            }

            extern void tiny_free(xmaybe_unused asciis name, voidp ptr, uxx bytes){
                inc::atom_sub(& g_used_bytes, bytes);
                inc::atom_sub(& g_alive_object, uxx{1});

                xdebug(im_free, name, ptr, bytes);
                ::free(ptr);
            }
        }

        namespace mixc::utils_memory::origin::memory{
            extern uxx used_bytes(){
                return inc::atom_load(& g_used_bytes);
            }

            extern uxx alive_object(){
                return inc::atom_load(& g_alive_object);
            }
        }

    #endif

    #include<malloc.h>

    namespace mixc::utils_memory::origin::memory{
        extern voidp malloc(uxx bytes){
            // 按 16 字节对齐
            bytes                   = (bytes + 0xf) & ~0xf;
            return ::malloc(bytes);
        }

        extern voidp malloc_aligned(uxx bytes, uxx align_bytes){
            #if xis_windows
                return ::_mm_malloc(bytes, align_bytes);
            #endif

            #if xis_linux
                return ::memalign(align_bytes, bytes);
            #endif
        }

        extern void mfree(voidp ptr){
            ::free(ptr);
        }

        extern void mfree_aligned(voidp ptr){
            #if xis_windows
                ::_mm_free(ptr);
            #endif

            #if xis_linux
                return ::free(ptr);
            #endif
        }
    }

#endif